using System;
using System.Threading;
using CSScriptLibrary;

namespace original
{
    class ScritedObject
    {
        private String textEmitter;
        private int myOrdinal;
        private Object compileLock;
        private bool uniqueMethodName;

        public void EmitTestText()
        {
            String methodNameSuffix = String.Empty;
            if (uniqueMethodName)
                methodNameSuffix = myOrdinal.ToString();

            if (compileLock != null)
                Monitor.Enter(compileLock);

            AsmHelper executor = new AsmHelper(CSScript.LoadMethod("public static void Emit" + methodNameSuffix + "() {" + this.textEmitter + "}"));

            if (compileLock != null)
                Monitor.Exit(compileLock);

            executor.Invoke("*.Emit" + methodNameSuffix);
        }

        public ScritedObject(int ObjectCount, bool UniqueMethodName, Object CompileLock)
        {
            this.textEmitter = @"Console.WriteLine(""I am emitter # " + ObjectCount.ToString() + @"""" + ");";
            this.myOrdinal = ObjectCount;
            this.uniqueMethodName = UniqueMethodName;
            this.compileLock = CompileLock;
        }
    }

    class Concurrency
    {
        static public void Test()
        {
            //CSScript.CacheEnabled = false;
            CSScript.CacheEnabled = true;
            CSScript.GlobalSettings.InMemoryAsssembly = true;
            CSScript.GlobalSettings.TargetFramework = "v3.5";
            CSScript.ShareHostRefAssemblies = true;

            Object compileLock = new Object();
            //no compile sync
            compileLock = null;
            bool UniqueMethodNames = false;
            //enforce unique method names
            //UniqueMethodNames = true;

            Thread emitThread1 = new Thread
            (
                delegate()
                {
                    for (int i = 0; i < 10; i++)
                    {
                        ScritedObject obj = new ScritedObject(i, UniqueMethodNames, compileLock);
                        obj.EmitTestText();
                    }
                }
            );

            Thread emitThread2 = new Thread
            (
                delegate()
                {
                    for (int i = 10; i < 30; i++)
                    {
                        ScritedObject obj = new ScritedObject(i, UniqueMethodNames, compileLock);
                        obj.EmitTestText();
                    }
                }
            );

            Thread emitThread3 = new Thread
            (
                delegate()
                {
                    for (int i = 20; i < 40; i++)
                    {
                        ScritedObject obj = new ScritedObject(i, UniqueMethodNames, compileLock);
                        obj.EmitTestText();
                    }
                }
            );

            emitThread1.Start();
            emitThread2.Start();
            emitThread3.Start();

            emitThread1.Join();
            emitThread2.Join();
            emitThread3.Join();

            Console.WriteLine("Done, any key to exit...");
            Console.ReadKey(false);
        }
    }
}